using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ContentOverContainer.Common;
using ContentOverContainer.Common.Converter;
using Roslyn.Compilers.CSharp;

namespace ContentOverContainer.Converter
{
    public static class CollConverter
    {
        /// <summary>
        /// Converts the coll expression. R-Coll1, R-Coll2
        /// </summary>
        /// <param name="exprSyntax">The expr syntax.</param>
        /// <param name="pConverterData">The p converter data.</param>
        /// <returns></returns>
        /// <author>Harald Binkle</author>
        public static ChangeNodeInfo ConvertCollExpression(BinaryExpressionSyntax exprSyntax, ConverterContext pConverterData)
        {
            //check if it is our new syntax
            var parentBinExpr = exprSyntax.Parent as BinaryExpressionSyntax;
            if (parentBinExpr == null) //it's not the desired one
                return new ChangeNodeInfo(exprSyntax);
            if (parentBinExpr.OperatorToken.ToString() != "^")//it's not the desired one
                return new ChangeNodeInfo(exprSyntax);

            var member = exprSyntax.Right as SimpleNameSyntax;
            var memberDecl = member.GetMemberDeclaration(pConverterData.SemanticModel);
            var memType = memberDecl.GetDeclarationType();
            var memMultiType = memberDecl.GetMultiplicityType();


            if (pConverterData.MultiplicityInfo.Kind == MultiplicityKind.Any)
            {
                //return new ChangeNodeInfo(Syntax.ParseExpression(string.Format("new {0}<{1}>({2})","List" ,memType,exprSyntax.Right))) { OrgSyntaxNode = parentBinExpr };
                List<ParameterPair> parameter = new List<ParameterPair>();
                parameter.Add(new ParameterPair() { Type = memMultiType, Name = member });
             
                //build Clear statement
                var invocationClearStatement = Syntax.ParseStatement(string.Format("var result = new {0}<{1}>();", "List", memType));
                //build Add statement
                StatementSyntax invocationAddStatement = Syntax.ParseStatement(string.Format("result.AddRange({0}); " + Environment.NewLine, member));
                var returnStatement = Syntax.ParseStatement(String.Format("return result;"));
                var methodBody = Syntax.Block(invocationClearStatement, invocationAddStatement, returnStatement);

                TypeSyntax exprType = pConverterData.MultiplicityInfo.Type;

                var composition = MethodComposer.BuildMethod("Coll", methodBody, parameter, exprType.ToString());
                var result = new ChangeNodeInfo(composition.InvocationCall) { OrgSyntaxNode = parentBinExpr };
                var methodSubstitution = new ChangeNodeMethodSubstitution()
                {
                    Class = parentBinExpr.FirstAncestorOrSelf<ClassDeclarationSyntax>(),
                    MethodDeclaration = composition.MethodDecl
                };
                result.MethodSubstitutionList.Add(methodSubstitution);
                return result;
            }

            if (pConverterData.MultiplicityInfo.Kind == MultiplicityKind.Option)
            {
                return new ChangeNodeInfo(Syntax.ParseExpression(string.Format("{2}!=null? new {0}<{1}>(){{{2}}}:new {0}<{1}>()", "List", memType, exprSyntax.Right))) { OrgSyntaxNode = parentBinExpr };
            }

            return new ChangeNodeInfo(exprSyntax);
        }
    }
}
